`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2017/11/22 10:23:13
// Design Name: 
// Module Name: hazard
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module hazard(
	//fetch stage
	output wire stallF,
	
	//decode stage
	input wire[4:0] rsD,rtD,
	input wire branchD,regdstD,jumpregD,
	output wire forwardaD,forwardbD,
	output wire flushD,
	output wire stallD,

	//execute stage
	input wire[4:0] rsE,rtE,
	input wire[4:0] writeregE,
	input wire regwriteE,
	input wire memtoregE,
	input wire alubusyE,
	// for cp0 read/write
	input wire cp0readE,
	input wire[4:0] cp0raddrE,
	output reg[1:0] forwardaE,forwardbE,
	output wire flushE,
	output wire stallE,
	output wire forwardcp0E,

	//mem stage
	input wire[4:0] writeregM,
	input wire regwriteM,
	input wire memtoregM,
	// for cp0 read/write
	input wire cp0weM,
	input wire[4:0] cp0waddrM,
	input wire except_jumpM,
	output wire flushM,
	output wire stallM,

	//write back stage
	input wire[4:0] writeregW,
	input wire regwriteW,
	output wire flushW,
	output wire stallW,

	//AXI
	input wire stallreg_from_if,
	input wire stallreg_from_mem
    );

	//forwarding sources to D stage (branch equality)
	assign forwardaD = (rsD != 0 & rsD == writeregM & regwriteM);
	assign forwardbD = (rtD != 0 & rtD == writeregM & regwriteM);
	
	// forwarding sources to E stage(CP0)
	assign forwardcp0E = (cp0readE != 0 && cp0weM != 0 && cp0raddrE == cp0waddrM);
	
	//forwarding sources to E stage (ALU)
    
	always @(*) begin
		forwardaE = 2'b00;
		forwardbE = 2'b00;
		if(rsE != 0) begin
			/* code */
			if(rsE == writeregM & regwriteM) begin
				/* code */
				forwardaE = 2'b10;
			end else if(rsE == writeregW & regwriteW) begin
				/* code */
				forwardaE = 2'b01;
			end
		end
		if(rtE != 0) begin
			/* code */
			if(rtE == writeregM & regwriteM) begin
				/* code */
				forwardbE = 2'b10;
			end else if(rtE == writeregW & regwriteW) begin
				/* code */
				forwardbE = 2'b01;
			end
		end
	end

	wire lwstallD,branchstallD,stall_all,flush_all;
	assign lwstallD = memtoregE & (rtE == rsD | rtE == rtD & regdstD);
	assign branchstallD = (branchD | jumpregD) &
				(regwriteE & 
				(writeregE == rsD | writeregE == rtD) |
				memtoregM &
				(writeregM == rsD | writeregM == rtD));
	assign stall_all = alubusyE | stallreg_from_if | stallreg_from_mem;
	assign flush_all = except_jumpM;

	//stalls
	assign {stallF,stallD,stallE,stallM,stallW} =	flush_all?	5'b00000:
													stall_all?		5'b11111:
													lwstallD?		5'b11000:
													branchstallD?	5'b11000:
													5'b00000;
	
	//flushes
	assign {flushD,flushE,flushM,flushW} =	flush_all?	4'b1111:
											stall_all?		4'b0000:
											lwstallD?		4'b0100:
											branchstallD?	4'b0100:
											4'b0000;

endmodule
